package com.gitee.qdbp.base.filter;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import com.gitee.qdbp.able.exception.ServiceException;
import com.gitee.qdbp.base.controlling.IControllingVars;
import com.gitee.qdbp.base.system.model.IAccount;
import com.gitee.qdbp.base.utils.SessionTools;
import com.gitee.qdbp.base.utils.WebTools;
import com.gitee.qdbp.general.common.api.oplog.model.AccessRecordBean;
import com.gitee.qdbp.general.common.api.oplog.service.IAccessRecordExecutor;
import com.gitee.qdbp.general.common.api.oplog.service.IAccessRecordParser;
import com.gitee.qdbp.tools.utils.JsonTools;
import com.gitee.qdbp.tools.utils.StringTools;

public class AccessRecordFilter implements Filter {

    private static final Logger log = LoggerFactory.getLogger(AccessRecordFilter.class);

    @Autowired
    private IAccessRecordExecutor accessRecordExecutor;

    private ExecutorService executors = Executors.newCachedThreadPool();

    private List<IAccessRecordParser> parsers = new ArrayList<>();

    /** 哪些参数不用记录日志 **/
    private Map<String, Boolean> ignoreParamKeys = new HashMap<>();

    public AccessRecordFilter(IControllingVars vars) {
        this.ignoreParamKeys.put("_", true);
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void destroy() {
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
            throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        WebTools wu = new WebTools(request);

        IAccount user = SessionTools.checkLoginUser();

        // 请求参数
        Map<String, Object> map = new HashMap<>();
        if (request != null) {
            for (Enumeration<String> e = request.getParameterNames(); e.hasMoreElements();) {
                String k = e.nextElement();
                if (!this.ignoreParamKeys.containsKey(k)) {
                    String v = StringTools.ellipsis(request.getParameter(k), 100); // 避免字符串过长
                    map.put(k, v);
                }
            }
        }
        String params = map.isEmpty() ? null : JsonTools.toJsonString(map);

        AccessRecordBean record = new AccessRecordBean();
        record.setTenantCode(user.getTenantCode()); // 租户编号
        record.setUserId(user.getId()); // 用户ID
        record.setUserName(user.getDisplayName()); // 用户名
        record.setIp(wu.getIpAddress()); // IP
        // record.setCity(); // 城市
        record.setRequestProtocol(request.getProtocol()); // 请求协议
        record.setRequestUrl(request.getRequestURL().toString()); // 请求URL
        record.setRequestParams(params); // 请求参数
        // record.setRequestDesc(); // 请求描述
        record.setRefererUrl(request.getHeader("referer")); // 来源页
        // record.setEntrance(); // 入口
        // record.setRefererType(); // 来源类型
        // record.setRefererKeyword(); // 来源关键词
        record.setUserAgent(request.getHeader("User-Agent")); // UserAgent
        // record.setBrowserType(); // 浏览器类型
        // record.setBrowserVersion(); // 浏览器版本
        // record.setOsType(); // 操作系统类型
        // record.setOsVersion(); // 操作系统版本
        // record.setDeviceType(); // 设备类型
        record.setCreateTime(new Date()); // 创建时间
        // record.setOptions(); // 选项

        executors.execute(new Runner(record));
    }

    private void saveToDb(AccessRecordBean record) {
        try {
            accessRecordExecutor.create(record);
        } catch (ServiceException e) {
            log.warn("Save access recored to db error. {}{}", e.toString(), JsonTools.newlineLogs(record), e);
        }
    }

    private void parseRecord(AccessRecordBean record) {
        for (IAccessRecordParser parser : this.parsers) {
            try {
                parser.parse(record);
            } catch (Exception ignore) {
            }
        }
    }

    private class Runner implements Runnable {

        private AccessRecordBean record;

        public Runner(AccessRecordBean record) {
            this.record = record;
        }

        @Override
        public void run() {
            parseRecord(record);
            saveToDb(record);
        }

    }

    public void setAccessRecordParser(List<IAccessRecordParser> parsers) {
        this.parsers.addAll(parsers);
    }

    /** 哪些参数不用记录日志 **/
    public void setIgnoreParamKeys(List<String> ignoreParamKeys) {
        this.ignoreParamKeys.clear();
        for (String string : ignoreParamKeys) {
            this.ignoreParamKeys.put(string, true);
        }
    }
}
